﻿using PerpheralDevice.IRepository;
using PerpheralDevice.Units;
using System.Diagnostics;
using System.Serialization;

namespace AppMachine.Domain.LogicCom.AppComs;

/// <summary>
///  应用组件(输入组件)
/// </summary>
public abstract class ComSwitch(IPerpDevRepository perpDevRepository, IComConfig comConfig, IComRepository comRepository)
        : AppComPrim(perpDevRepository, comConfig, comRepository) {

    public abstract bool IsDisabled { get; }
    public abstract bool IsReversed { get; }
    public abstract bool? IsOpen { get; }
    /// <summary>
    /// 等待开关处于指定状态；cancellationToken取消等待抛出异常终止顺序程序流
    /// </summary>
    /// <param name="isOpenState">指定开关状态(是否为开)</param>
    /// <param name="timeoutMilisecs">等待超时时间(毫秒)</param>
    /// <param name="cancellationToken">取消等待令牌</param>
    /// <returns></returns>
    public ComSwitch Wait(bool isOpenState, int timeoutMilisecs, CancellationToken cancellationToken = default) {

        Stopwatch tempStopwatch = Stopwatch.StartNew();
        bool tempHasWarnLog = false;
        while (!cancellationToken.IsCancellationRequested && this.IsOpen != isOpenState) {
            if (tempStopwatch.ElapsedMilliseconds > timeoutMilisecs) {
                if (!tempHasWarnLog) {
                    tempHasWarnLog = true;
                    this._logger.Warn($"等待超时({tempStopwatch.ElapsedMilliseconds}ms)=>({this.TagName})状态({isOpenState})超时({timeoutMilisecs}ms)");
                }
            }
            Stopwatch.StartNew().Delay(10);
        }

        this._logger.Info($"等待结束({tempStopwatch.ElapsedMilliseconds}ms)=>开关({this.TagName})状态({isOpenState})");

        if (cancellationToken.IsCancellationRequested) {
            cancellationToken.ThrowIfCancellationRequested();
        }

        return this;
    }

    /// <summary>
    /// 等待开关列表处于指定状态；cancellationToken取消等待抛出异常终止顺序程序流
    /// </summary>
    /// <param name="isOpenState">指定开关状态(是否为开)</param>
    /// <param name="timeoutMilisecs">等待超时时间(毫秒)</param>
    /// <param name="cancellationToken">取消等待令牌</param>
    /// <param name="comSwitchList">等待开关列表</param>
    public static void Wait(bool isOpenState, int timeoutMilisecs, CancellationToken cancellationToken = default, params ComSwitch[] comSwitchList) {

        Stopwatch tempStopwatch = Stopwatch.StartNew();
        bool tempHasWarnLog = false;
        while (!cancellationToken.IsCancellationRequested && comSwitchList.Any(it => it.IsOpen != isOpenState)) {
            if (!tempHasWarnLog && tempStopwatch.ElapsedMilliseconds > timeoutMilisecs) {
                if (!tempHasWarnLog) {
                    tempHasWarnLog = true;
                    comSwitchList.FirstOrDefault()?._logger
                        .Info($"等待超时({tempStopwatch.ElapsedMilliseconds}ms)=>开关({string.Join(',', comSwitchList.Select(it => $"{it.TagName}:{it.IsOpen}<=等待状态({isOpenState})"))})");
                }
            }
            Stopwatch.StartNew().Delay(10);
        }

        comSwitchList.FirstOrDefault()?._logger
            .Info($"等待结束({tempStopwatch.ElapsedMilliseconds}ms)=>开关({string.Join(',', comSwitchList.Select(it => $"{it.TagName}:{it.IsOpen}<=等待状态({isOpenState})"))})");

        if (cancellationToken.IsCancellationRequested) {
            cancellationToken.ThrowIfCancellationRequested();
        }

    }

    public static void Wait(int timeoutMilisecs, CancellationToken cancellationToken = default, params Tuple<bool, ComSwitch>[] comSwitchList) {

        Stopwatch tempStopwatch = Stopwatch.StartNew();
        bool tempHasWarnLog = false;

        var tempComSwitchListOpen = comSwitchList.Where(it => it.Item1).Select(it => it.Item2);
        var tempComSwitchListOpenNot = comSwitchList.Where(it => !it.Item1).Select(it => it.Item2);

        while (!cancellationToken.IsCancellationRequested && tempComSwitchListOpen.Any(it => it.IsOpen ?? false) && tempComSwitchListOpenNot.Any(it => !(it.IsOpen ?? true))) {
            if (!tempHasWarnLog && tempStopwatch.ElapsedMilliseconds > timeoutMilisecs) {
                if (!tempHasWarnLog) {
                    tempHasWarnLog = true;
                    comSwitchList.FirstOrDefault()?.Item2._logger
                        .Info($"等待超时({tempStopwatch.ElapsedMilliseconds}ms)=>开关({string.Join(',', comSwitchList.Select(it => $"{it.Item2.TagName}:{it.Item2.IsOpen}<=等待状态({it.Item1})"))})");
                }
            }
            Stopwatch.StartNew().Delay(10);
        }

        comSwitchList.FirstOrDefault()?.Item2._logger
                .Info($"等待结束({tempStopwatch.ElapsedMilliseconds}ms)=>开关({string.Join(',', comSwitchList.Select(it => $"{it.Item2.TagName}:{it.Item2.IsOpen}<=等待状态({it.Item1})"))})");

        if (cancellationToken.IsCancellationRequested) {
            cancellationToken.ThrowIfCancellationRequested();
        }

    }

}
